#![allow(unused_variables)]
#![allow(dead_code)]

use crate::prequire::{
  adb::{shell::ShellCmd, start_app},
  BinaryCommand,
};
use crate::project::conf::project_conf::ProjectConf;
use crate::project::{Project, CaptureScenes};
use anyhow::{anyhow, Result};
use chrono::prelude::*;
use clap::Subcommand;
use std::fmt;
use std::path::{Path, PathBuf};
use std::thread;
use std::time::Duration;
use indicatif::{MultiProgress, ProgressStyle};
use std::fs::create_dir_all;

mod mtt;
mod old;

pub use mtt::keyword_auto_search::KeywordAutoSearchCatcher;
pub use old::Catcher as OldCatcher;

#[derive(Debug)]
pub enum CaptureCategory {
  Screenshot,
  Train,
}

impl fmt::Display for CaptureCategory {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{:?}", self)
  }
}



pub struct CatchOptions {
  // out_dir: PathBuf,
  // num: u64,
  train: bool,
  preprocess: bool,
  scene: CaptureScenes,
}

impl CatchOptions {
  pub fn new() -> Self {
    CatchOptions {
      // out_dir: PathBuf::new(),
      // num: 1,
      train: false,
      preprocess: false,
      scene: CaptureScenes::None,
    }
  }
  // pub fn set_out_dir<P: AsRef<Path>>(&mut self, out_dir: P) -> &mut Self {
  //   self.out_dir.clear();
  //   self.out_dir.push(out_dir.as_ref());
  //   self
  // }
  // pub fn set_num(&mut self, num: u64) -> &mut Self {
  //   self.num = num;
  //   self
  // }
  pub fn set_train(&mut self, train: bool) -> &mut Self {
    self.train = train;
    self
  }
  pub fn set_preprocess(&mut self, preprocess: bool) -> &mut Self {
    self.preprocess = preprocess;
    self
  }
  pub fn set_scene(&mut self, scene: CaptureScenes) -> &mut Self {
    self.scene = scene;
    self
  }
  pub fn screenshot<P: AsRef<Path>>(
    &self,
    conf: &ProjectConf,
    out_dir: P,
    num: u64,
  ) -> Result<Vec<String>> {
    match self.scene {
      // CaptureScenes::Keyword => KeywordSearchCatcher::new(conf).screenshot(out_dir, num, &self),
      CaptureScenes::Keyword => KeywordAutoSearchCatcher::new(conf).screenshot(out_dir, num, &self),
      _ => Err(anyhow!("场景{:?}没有实现catcher", self.scene)),
    }
  }
}

pub trait Catcher {
  fn screenshot<P: AsRef<Path>>(
    &self,
    out_dir: P,
    num: u64,
    opts: &CatchOptions,
  ) -> Result<Vec<String>> {
    Err(anyhow!("not impl for screenshot"))
  }
  fn record(&self, _opts: CatchOptions) -> Result<&str> {
    Err(anyhow!("not impl for record"))
  }
  fn ensure_out_dir(&self, out_dir: &Path) {
    println!("ensure_out_dir<{}>", out_dir.display());
    create_dir_all(out_dir).expect("create_dir_all fail!");
  }

  fn ensure_out_raw_dir(&self, out_dir: &Path) -> PathBuf {
    println!("ensure_raw_dir<{}/raw>", out_dir.display());
    let out_raw_path = out_dir.join("raw");
    create_dir_all(&out_raw_path).expect("create_dir_all fail!");
    out_raw_path
  }

  fn create_indicator(&self) -> (MultiProgress, ProgressStyle) {
    let m = MultiProgress::new();
    let sty =
      ProgressStyle::with_template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
        .unwrap()
        .progress_chars("##-");

    (m, sty)
  }
}

#[derive(Debug, Subcommand)]
pub enum ProjectScreenCommands {
  Capture {
    #[arg(short, long, default_value_t = 1, default_missing_value = "1")]
    num: usize,

    #[arg(short, long)]
    train: bool,

    #[arg(short, long, default_value_t = false)]
    preprocess: bool,

    #[arg(short, long, value_enum)]
    scene: CaptureScenes,
  },
}

pub fn serve_commands(proj: &Project, command: &ProjectScreenCommands) {
  match command {
    &ProjectScreenCommands::Capture {
      num,
      train,
      preprocess,
      scene,
    } => {
      start_app(&proj.proj_conf.app.name).expect("failed start app");
      thread::sleep(Duration::from_millis(5000));
      let fragment = iif!(
        train,
        format!(
          "{}/{:?}",
          &proj.proj_conf.app.capture_dir.display(),
          CaptureCategory::Train
        ),
        format!(
          "{}/{:?}",
          &proj.proj_conf.app.capture_dir.display(),
          CaptureCategory::Screenshot
        )
      );
      let capture_dir = format!(
        "{}/{}_{}",
        proj.location.as_os_str().to_str().unwrap(),
        fragment,
        Utc::now().timestamp_millis(),
      );

      ShellCmd::new(
        &["input swipe 600 2155 600 1405"],
        Some(Box::new(|_| String::from(""))),
      )
      .exec()
      .expect("shell input swipe failed");

      let ctr = OldCatcher::new(&capture_dir, preprocess);
      if let Ok(success) = ctr.capture_mtt_list(num) {
        if success {
          println!(
            "截图成功保存在{}!",
            proj.proj_conf.app.capture_dir.display()
          );
        }
      }
    }
  }
}
